package org.framework.lazy.cloud.network.heartbeat.server.standalone.application.impl;

import jakarta.annotation.Resource;
import org.framework.lazy.cloud.network.heartbeat.common.enums.ChannelProtocolType;
import org.framework.lazy.cloud.network.heartbeat.common.enums.ChannelProxyType;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.LazyProxyFlowApplication;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.assembler.LazyProxyFlowDTOAssembler;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.assembler.LazyProxyPerDayFlowDTOAssembler;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.proxy.flow.*;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.proxy.per.day.flow.LazyProxyPerDayFlowStoryCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.dto.LazyClientProxyFlowDTO;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.dto.LazyProxyFlowDTO;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.dto.LazyVisitorFlowDTO;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.domain.model.lazy.proxy.flow.LazyProxyFlow;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.domain.model.lazy.proxy.flow.LazyProxyFlowRepository;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.domain.model.lazy.proxy.per.day.flow.LazyProxyPerDayFlow;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.domain.model.lazy.proxy.per.day.flow.LazyProxyPerDayFlowRepository;
import org.wu.framework.core.utils.ObjectUtils;
import org.wu.framework.lazy.orm.database.lambda.domain.LazyPage;
import org.wu.framework.lazy.orm.web.plus.stereotype.LazyApplication;
import org.wu.framework.web.response.Result;
import org.wu.framework.web.response.ResultFactory;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * describe 代理流量
 *
 * @author Jia wei Wu
 * @date 2025/06/06 11:39 晚上
 * @see org.wu.framework.lazy.orm.core.persistence.reverse.lazy.ddd.DefaultDDDLazyApplicationImpl
 **/
@LazyApplication
public class LazyProxyFlowApplicationImpl implements LazyProxyFlowApplication {

    @Resource
    LazyProxyFlowRepository lazyProxyFlowRepository;
    @Resource
    LazyProxyPerDayFlowRepository lazyProxyPerDayFlowRepository;


    /**
     * describe 新增代理流量
     *
     * @param lazyProxyFlowStoryCommand 新增代理流量
     * @return {@link Result<LazyProxyFlow>} 代理流量新增后领域对象
     * @author Jia wei Wu
     * @date 2025/06/06 11:39 晚上
     **/

    @Override
    public Result<LazyProxyFlow> story(LazyProxyFlowStoryCommand lazyProxyFlowStoryCommand) {
        LazyProxyFlow lazyProxyFlow = LazyProxyFlowDTOAssembler.INSTANCE.toLazyProxyFlow(lazyProxyFlowStoryCommand);
        return lazyProxyFlowRepository.story(lazyProxyFlow);
    }

    /**
     * 流量增长存储
     * 访客 ID 访客 端口必须
     *
     * @param lazyProxyFlowStoryCommand 代理流量
     * @return
     */
    @Override
    public Result<LazyProxyFlow> flowIncreaseStory(LazyProxyFlowStoryCommand lazyProxyFlowStoryCommand) {
        String clientId = lazyProxyFlowStoryCommand.getClientId();
        String ip = lazyProxyFlowStoryCommand.getIp();
        ChannelProtocolType protocolType = lazyProxyFlowStoryCommand.getProtocolType();
        ChannelProxyType proxyType = lazyProxyFlowStoryCommand.getProxyType();
        Integer port = lazyProxyFlowStoryCommand.getPort();


        Integer realOutFlow = ObjectUtils.isEmpty(lazyProxyFlowStoryCommand.getOutFlow()) ? 0 : lazyProxyFlowStoryCommand.getOutFlow();
        Integer realInFlow = ObjectUtils.isEmpty(lazyProxyFlowStoryCommand.getInFlow()) ? 0 : lazyProxyFlowStoryCommand.getInFlow();
        // 查询是否存在已有流量 而后进行统计汇总
        LazyProxyFlow findOneLazyProxyFlowQuery = new LazyProxyFlow();
        findOneLazyProxyFlowQuery.setClientId(clientId);
        findOneLazyProxyFlowQuery.setPort(port);
        findOneLazyProxyFlowQuery.setIp(ip);
        findOneLazyProxyFlowQuery.setProtocolType(protocolType);
        findOneLazyProxyFlowQuery.setProxyType(proxyType);


        lazyProxyFlowRepository.findOne(findOneLazyProxyFlowQuery).accept(existVisitorFlow -> {
            Integer inFlow = existVisitorFlow.getInFlow();
            Integer outFlow = existVisitorFlow.getOutFlow();
            if (!ObjectUtils.isEmpty(inFlow)) {
                lazyProxyFlowStoryCommand.setInFlow(realInFlow + inFlow);
            }
            if (!ObjectUtils.isEmpty(outFlow)) {
                lazyProxyFlowStoryCommand.setOutFlow(realOutFlow + outFlow);
            }
        });
        LazyProxyFlow lazyLazyProxyFlow = LazyProxyFlowDTOAssembler.INSTANCE.toLazyProxyFlow(lazyProxyFlowStoryCommand);
        lazyProxyFlowRepository.story(lazyLazyProxyFlow);

        // 日流量统计
        LazyProxyPerDayFlowStoryCommand lazyProxyPerDayFlowStoryCommand = new LazyProxyPerDayFlowStoryCommand();
        lazyProxyPerDayFlowStoryCommand.setClientId(clientId);
        lazyProxyPerDayFlowStoryCommand.setPort(port);
        lazyProxyPerDayFlowStoryCommand.setIp(ip);
        lazyProxyPerDayFlowStoryCommand.setProtocolType(protocolType);
        lazyProxyPerDayFlowStoryCommand.setProxyType(proxyType);
        lazyProxyPerDayFlowStoryCommand.setDay(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

        lazyProxyPerDayFlowStoryCommand.setOutFlow(realOutFlow);
        lazyProxyPerDayFlowStoryCommand.setInFlow(realInFlow);


        LazyProxyPerDayFlow findOneLazyProxyPerDayFlowQuery = new LazyProxyPerDayFlow();
        findOneLazyProxyPerDayFlowQuery.setClientId(clientId);
        findOneLazyProxyPerDayFlowQuery.setPort(port);
        findOneLazyProxyPerDayFlowQuery.setDay(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

        findOneLazyProxyPerDayFlowQuery.setIp(ip);
        findOneLazyProxyPerDayFlowQuery.setProtocolType(protocolType);
        findOneLazyProxyPerDayFlowQuery.setProxyType(proxyType);

        lazyProxyPerDayFlowRepository.findOne(findOneLazyProxyPerDayFlowQuery).accept(existLazyProxyPerDayFlow -> {
            Integer inFlow = existLazyProxyPerDayFlow.getInFlow();
            Integer outFlow = existLazyProxyPerDayFlow.getOutFlow();
            if (!ObjectUtils.isEmpty(inFlow)) {
                lazyProxyPerDayFlowStoryCommand.setInFlow(realInFlow + inFlow);
            }
            if (!ObjectUtils.isEmpty(outFlow)) {
                lazyProxyPerDayFlowStoryCommand.setOutFlow(realOutFlow + outFlow);
            }
        });
        LazyProxyPerDayFlow lazyVisitorPortPerDayFlow = LazyProxyPerDayFlowDTOAssembler.INSTANCE.toLazyProxyPerDayFlow(lazyProxyPerDayFlowStoryCommand);
        lazyProxyPerDayFlowRepository.story(lazyVisitorPortPerDayFlow);

        return ResultFactory.successOf();

    }


    /**
     * describe 批量新增代理流量
     *
     * @param lazyProxyFlowStoryCommandList 批量新增代理流量
     * @return {@link Result<List<LazyProxyFlow>>} 代理流量新增后领域对象集合
     * @author Jia wei Wu
     * @date 2025/06/06 11:39 晚上
     **/

    @Override
    public Result<List<LazyProxyFlow>> batchStory(List<LazyProxyFlowStoryCommand> lazyProxyFlowStoryCommandList) {

        List<LazyProxyFlow> lazyProxyFlowList = lazyProxyFlowStoryCommandList
                .stream()
                .map(LazyProxyFlowDTOAssembler.INSTANCE::toLazyProxyFlow

                )
                .collect(Collectors.toList());
        return lazyProxyFlowRepository.batchStory(lazyProxyFlowList);
    }

    /**
     * describe 更新代理流量
     *
     * @param lazyProxyFlowUpdateCommand 更新代理流量
     * @return {@link Result<LazyProxyFlow>} 代理流量领域对象
     * @author Jia wei Wu
     * @date 2025/06/06 11:39 晚上
     **/

    @Override
    public Result<LazyProxyFlow> updateOne(LazyProxyFlowUpdateCommand lazyProxyFlowUpdateCommand) {
        LazyProxyFlow lazyProxyFlow = LazyProxyFlowDTOAssembler.INSTANCE.toLazyProxyFlow(lazyProxyFlowUpdateCommand);
        return lazyProxyFlowRepository.story(lazyProxyFlow);
    }

    /**
     * describe 查询单个代理流量
     *
     * @param lazyProxyFlowQueryOneCommand 查询单个代理流量
     * @return {@link Result<LazyProxyFlowDTO>} 代理流量DTO对象
     * @author Jia wei Wu
     * @date 2025/06/06 11:39 晚上
     **/

    @Override
    public Result<LazyProxyFlowDTO> findOne(LazyProxyFlowQueryOneCommand lazyProxyFlowQueryOneCommand) {
        LazyProxyFlow lazyProxyFlow = LazyProxyFlowDTOAssembler.INSTANCE.toLazyProxyFlow(lazyProxyFlowQueryOneCommand);
        return lazyProxyFlowRepository.findOne(lazyProxyFlow).convert(LazyProxyFlowDTOAssembler.INSTANCE::fromLazyProxyFlow);
    }

    /**
     * describe 查询多个代理流量
     *
     * @param lazyProxyFlowQueryListCommand 查询多个代理流量
     * @return {@link Result<List<LazyProxyFlowDTO>>} 代理流量DTO对象
     * @author Jia wei Wu
     * @date 2025/06/06 11:39 晚上
     **/

    @Override
    public Result<List<LazyProxyFlowDTO>> findList(LazyProxyFlowQueryListCommand lazyProxyFlowQueryListCommand) {
        LazyProxyFlow lazyProxyFlow = LazyProxyFlowDTOAssembler.INSTANCE.toLazyProxyFlow(lazyProxyFlowQueryListCommand);
        return lazyProxyFlowRepository.findList(lazyProxyFlow).convert(lazyProxyFlows -> lazyProxyFlows.stream().map(LazyProxyFlowDTOAssembler.INSTANCE::fromLazyProxyFlow).collect(Collectors.toList()));
    }

    /**
     * describe 分页查询多个代理流量
     *
     * @param lazyProxyFlowQueryListCommand 分页查询多个代理流量
     * @return {@link Result<LazyPage<LazyProxyFlowDTO>>} 分页代理流量DTO对象
     * @author Jia wei Wu
     * @date 2025/06/06 11:39 晚上
     **/

    @Override
    public Result<LazyPage<LazyProxyFlowDTO>> findPage(int size, int current, LazyProxyFlowQueryListCommand lazyProxyFlowQueryListCommand) {
        LazyProxyFlow lazyProxyFlow = LazyProxyFlowDTOAssembler.INSTANCE.toLazyProxyFlow(lazyProxyFlowQueryListCommand);
        return lazyProxyFlowRepository.findPage(size, current, lazyProxyFlow).convert(page -> page.convert(LazyProxyFlowDTOAssembler.INSTANCE::fromLazyProxyFlow));
    }

    /**
     * describe 删除代理流量
     *
     * @param lazyProxyFlowRemoveCommand 删除代理流量
     * @return {@link Result<LazyProxyFlow>} 代理流量
     * @author Jia wei Wu
     * @date 2025/06/06 11:39 晚上
     **/

    @Override
    public Result<LazyProxyFlow> remove(LazyProxyFlowRemoveCommand lazyProxyFlowRemoveCommand) {
        LazyProxyFlow lazyProxyFlow = LazyProxyFlowDTOAssembler.INSTANCE.toLazyProxyFlow(lazyProxyFlowRemoveCommand);
        return lazyProxyFlowRepository.remove(lazyProxyFlow);
    }

    /**
     * 根据客户端查询流量
     *
     * @param size                          分页大小
     * @param current                       分页
     * @param lazyProxyFlowQueryListCommand 查询条件
     * @return {@link Result<LazyPage<   LazyVisitorFlowDTO   >>} 分页访客端流量DTO对象
     */
    @Override
    public Result<LazyPage<LazyClientProxyFlowDTO>> findClientFlowPage(int size, int current, LazyProxyFlowQueryListCommand lazyProxyFlowQueryListCommand) {
        LazyProxyFlow lazyLazyProxyFlow = LazyProxyFlowDTOAssembler.INSTANCE.toLazyProxyFlow(lazyProxyFlowQueryListCommand);
        return lazyProxyFlowRepository.findPageGroupByClientId(size, current, lazyLazyProxyFlow).convert(lazyProxyFlowLazyPage -> {
            List<String> clientIdList = lazyProxyFlowLazyPage
                    .getRecords()
                    .stream()
                    .map(LazyProxyFlow::getClientId)
                    .toList();
            List<LazyProxyFlow> lazyLazyProxyFlowList = lazyProxyFlowRepository.findListByClientIds(clientIdList);


            // 根据客户端进行分组

            List<LazyProxyFlowDTO> lazyLazyProxyFlowDTOList = lazyLazyProxyFlowList.stream().map(LazyProxyFlowDTOAssembler.INSTANCE::fromLazyProxyFlow).toList();


            Map<String/*客户端ID*/, List<LazyProxyFlowDTO>> client_port_flow_map = lazyLazyProxyFlowDTOList.stream().collect(Collectors.groupingBy(LazyProxyFlowDTO::getClientId));

            Map<String/*客户端ID*/, Integer/*客户端进口流量*/> client_in_flow = lazyLazyProxyFlowDTOList.stream()
                    .collect(
                            Collectors.groupingBy(LazyProxyFlowDTO::getClientId,
                                    Collectors.summingInt(LazyProxyFlowDTO::getInFlowSize)));

            Map<String/*客户端ID*/, Integer/*客户端出口流量*/> client_out_flow = lazyLazyProxyFlowDTOList.stream()
                    .collect(
                            Collectors.groupingBy(LazyProxyFlowDTO::getClientId,
                                    Collectors.summingInt(LazyProxyFlowDTO::getOutFlowSize)));

            return lazyProxyFlowLazyPage.convert(lazyProxyFlow -> {
                String clientId = lazyProxyFlow.getClientId();
                LazyClientProxyFlowDTO lazyClientProxyFlowDTO = new LazyClientProxyFlowDTO();
                lazyClientProxyFlowDTO.setClientId(clientId);
                lazyClientProxyFlowDTO.setInFlow(client_in_flow.getOrDefault(clientId, 0));
                lazyClientProxyFlowDTO.setOutFlow(client_out_flow.getOrDefault(clientId, 0));
                lazyClientProxyFlowDTO.setLazyProxyFlowDTOList(client_port_flow_map.getOrDefault(clientId, new ArrayList<>()));
                return lazyClientProxyFlowDTO;
            });
        });
    }

}